package modlgen

import (
	l4g "code.google.com/p/log4go"
	"fmt"
	"strconv"
	"strings"
)

type mdoAttrClass uint8

const (
	MDO_ATTR_CLASS_BASIC = iota
	MDO_ATTR_CLASS_TIME
	MDO_ATTR_CLASS_ARRAY
	MDO_ATTR_CLASS_SLICE
	MDO_ATTR_CLASS_STRUCT
)

type mdoAttrDef struct {
	typeId              int
	attributeId         int
	name                string
	attributeTypeShort  string
	attributeTypeFull   string
	attributeClass      mdoAttrClass
	collection          bool
	collectionTypeShort string
	collectionTypeFull  string
	collectionClass     mdoAttrClass
	persistenceType     string
	definedOnLineNum    int
}

func newMdoAttrDef(typeDef *mdoTypeDef) mdoAttrDef {
	l4g.Trace("Parsing %s as attribute definition from line %d of file %s", typeDef.fileReader.currentContentLineParts, typeDef.fileReader.lineIdx, typeDef.fileReader.filename)
	var attr mdoAttrDef
	attr.typeId = typeDef.typeId
	attr.definedOnLineNum = typeDef.fileReader.lineIdx
	var err error
	attr.attributeId, err = strconv.Atoi(typeDef.fileReader.currentContentLineParts[0])
	if err != nil {
		panic(fmt.Sprintf("Expecting integer attribute id, found \"%s\", line %d of file %s", typeDef.fileReader.currentContentLineParts[0], typeDef.fileReader.lineIdx, typeDef.fileReader.filename))
	}

	if len(typeDef.fileReader.currentContentLineParts) < 2 {
		panic(fmt.Sprintf("Missing attribute name, line %d of file %s", typeDef.fileReader.lineIdx, typeDef.fileReader.filename))
	}
	attr.name = typeDef.fileReader.currentContentLineParts[1]

	if len(typeDef.fileReader.currentContentLineParts) < 3 {
		panic(fmt.Sprintf("Missing attribute type, line %d of file %s", typeDef.fileReader.lineIdx, typeDef.fileReader.filename))
	}
	attr.attributeTypeFull = typeDef.fileReader.currentContentLineParts[2]
	if strings.Contains(attr.attributeTypeFull, ".") {
		splitType := strings.Split(attr.attributeTypeFull, ".")
		attr.attributeTypeShort = splitType[1]
	} else {
		attr.attributeTypeShort = attr.attributeTypeFull
	}
	attr.attributeClass = getClass(attr.attributeTypeFull, typeDef.fileReader)
	switch attr.attributeClass {
	case MDO_ATTR_CLASS_SLICE:
		attr.collection = true
		attr.collectionTypeFull = attr.attributeTypeFull[2:]
		attr.collectionClass = getClass(attr.collectionTypeFull, typeDef.fileReader)
	case MDO_ATTR_CLASS_ARRAY:
		attr.collection = true
		attr.collectionTypeFull = attr.attributeTypeFull[strings.Index(attr.attributeTypeShort, "]")+1:]
		attr.collectionClass = getClass(attr.collectionTypeFull, typeDef.fileReader)
	}
	if strings.Contains(attr.collectionTypeFull, ".") {
		splitType := strings.Split(attr.collectionTypeFull, ".")
		attr.collectionTypeShort = splitType[1]
	} else {
		attr.collectionTypeShort = attr.collectionTypeFull
	}

	if len(typeDef.fileReader.currentContentLineParts) < 4 {
		attr.persistenceType = "persistent"
	} else {
		attr.persistenceType = typeDef.fileReader.currentContentLineParts[3]
		switch attr.persistenceType {
		case "persistent", "non-persistent", "ephemeral":
			// recognized persistance types
		default:
			panic(fmt.Sprintf("Unrecognized persistence type \"%s\", line %d of file %s", typeDef.fileReader.currentContentLineParts[3], typeDef.fileReader.lineIdx, typeDef.fileReader.filename))
		}
	}

	if len(typeDef.fileReader.currentContentLineParts) > 6 {
		panic(fmt.Sprintf("Unrecognized options \"%s\", line %d of file %s", typeDef.fileReader.currentContentLineParts[5:], typeDef.fileReader.lineIdx, typeDef.fileReader.filename))
	}

	return attr
}

func getClass(typeName string, fileReader *fileReader) mdoAttrClass {
	switch typeName {
	case "byte", "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "float32", "float64", "string":
		return MDO_ATTR_CLASS_BASIC
	case "time.Time":
		return MDO_ATTR_CLASS_TIME
	default:
		switch {
		case strings.HasPrefix(typeName, "[]"):
			return MDO_ATTR_CLASS_SLICE
		case strings.HasPrefix(typeName, "["):
			return MDO_ATTR_CLASS_ARRAY
		default:
			return MDO_ATTR_CLASS_STRUCT
		}
	}
	panic(fmt.Sprintf("Couldn't determine attribute class for \"%s\", line %d of file %s)", typeName, fileReader.lineIdx, fileReader.filename))
}
